package com.spzx.cart.service.impl;

import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder;
import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.SkuPrice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CartServiceImpl implements ICartService {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RemoteProductService remoteProductService;

    /**
     *
     * 添加购物车
     * @param skuId
     * @param skuNum
     */
    @Override
    public void addTocart(Long skuId, Integer skuNum) {
        //获取当前登录对象
        Long userId = SecurityContextHolder.getUserId();
        //构建当前对象的购物车key
        String cartKey  = "user:cart:"+userId;
        //为购物车绑定hashkey操作对象
        BoundHashOperations<String,String, CartInfo> ops = redisTemplate.boundHashOps(cartKey);

        //因为绑定关系中，hashkey需要String类型
        String hashKey = skuId.toString();
        int skuNumsMax=99;
        //查看我的购物车中有没有这个传入的(要判断是第一添加还是已不是第一次添加了)
        if(ops.hasKey(hashKey)){
            //购物车中有这个key说明已经不是第一次添加商品了
            //购物车中已经存在这个商品了。那么我们需要对这个sku的数量进行添加。那么我们的数量正是hashkey对应的一个value的值
            CartInfo cartInfo = ops.get(hashKey);
            //将前端传给我们的数据加到商品的，但是还没有给购物车商品信息设置上
            Integer skuNums = cartInfo.getSkuNum()+skuNum;

            //但是我们约定了sku的数量是不超过99的
            //超过了最多也就是99，如果没有超过就可以
            cartInfo.setSkuNum(skuNums > skuNumsMax ? skuNumsMax:skuNums);
            cartInfo.setUpdateTime(new Date());

            //放在缓存中
            ops.put(hashKey,cartInfo);
        }else{
            //购物车的商品不能超过50个
            Long size = ops.size();
            if(++size>4){
                throw new ServiceException("超过购物车商品最大数量4！！！");
            }
            //说明是第一次添加到购物车中，需要将cartInfo的内容全部加到这个map中
            //购物车中没有，那么就构建购物车对象，往里面塞东西呗
            CartInfo cartInfo = new CartInfo();

            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum > skuNumsMax ? skuNumsMax:skuNum);
            //cartInfo.setUpdateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            cartInfo.setCreateTime(new Date());
            //cartinfo中想要的根据前端传过来的数据，我们都可以进行设置了
            //但是还有一些需要我们自己查询
            /**
             *
             * 放入购物车时的价格，以及有一些其他信息，在produxt模块，
             * 所以要进行远程调用
             */
            R<ProductSku> productSku = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
            if(productSku.getCode()==R.FAIL){
                //因为是远程调用，可能报错,进行降级熔断
                throw new ServiceException(productSku.getMsg());
            }
            ProductSku productSkuData = productSku.getData();
            cartInfo.setSkuId(skuId);
            cartInfo.setThumbImg(productSkuData.getThumbImg());
            cartInfo.setSkuName(productSkuData.getSkuName());
            /**
             *
             * 调用远程商品读物获取商品实时价格
             */
            R<SkuPrice> skuPriceResult = remoteProductService.getSkuPrice(skuId, SecurityConstants.INNER);
            if(skuPriceResult.getCode()==R.FAIL){
                //远程调用会出现熔断
                throw new ServiceException(skuPriceResult.getMsg());
            }
            SkuPrice skuPriceResultData = skuPriceResult.getData();
            cartInfo.setCartPrice(skuPriceResultData.getSalePrice());
            cartInfo.setSkuPrice(skuPriceResultData.getSalePrice());


            ops.put(hashKey,cartInfo);
        }

    }

    /**
     *
     * 查看购物车
     * @return
     */
    @Override
    public List<CartInfo> getCartList() {
        // 获取当前登录用户的id
        Long userId = SecurityContextHolder.getUserId();
        String cartKey  = "user:cart:"+userId;
        // 获取数据
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            List<CartInfo> infoList = cartInfoList.stream()
                    .sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                    .collect(Collectors.toList());

            //获取skuId列表
            List<Long> skuIdList = infoList.stream().map(CartInfo::getSkuId).collect(Collectors.toList());
            //查询商品的实时价格
            R<List<SkuPrice>> SkuPriceListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if (R.FAIL == SkuPriceListResult.getCode()) {
                throw new ServiceException(SkuPriceListResult.getMsg());
            }
            //设置最新的价格
            List<SkuPrice> skuPriceList = SkuPriceListResult.getData();
            Map<Long, BigDecimal> skuIdToPriceMap = skuPriceList.stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));

//            infoList.forEach(item -> {
//                //设置实时价格
//                item.setSkuPrice(skuIdToPriceMap.get(item.getSkuId()));
//            });
            //更新商品最新价格：更新内存中商品最新价格，而不是购物车中价格。因为没有重新放回到购物车中。
            for (CartInfo cartInfo : infoList) {
                cartInfo.setSkuPrice(skuIdToPriceMap.get(cartInfo.getSkuId()));
            }
            return infoList ;
        }
        return new ArrayList<>();
    }
    /*@Override
    public List<CartInfo> getCartList() {
        //获取当前登录对象
        Long userId = SecurityContextHolder.getUserId();
        //构建当前对象的购物车key
        String cartKey  = "user:cart:"+userId;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if(!CollectionUtils.isEmpty(cartInfoList)){
            //对购物车的商品创建时间进行排序
            List<CartInfo> infoList = cartInfoList.stream().sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime())).collect(Collectors.toList());
            //查询有哪些商品
            //将skuid也进行收集
            List<Long> skuIdList = infoList.stream().map(CartInfo::getId).collect(Collectors.toList());
            //查询商品的实时价格
            R<List<SkuPrice>> SkuPriceListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if (R.FAIL == SkuPriceListResult.getCode()) {
                throw new ServiceException(SkuPriceListResult.getMsg());
            }
            Map<Long, BigDecimal> skuIdToPriceMap = SkuPriceListResult.getData().stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));

            infoList.forEach(item -> {
                //设置实时价格
                item.setSkuPrice(skuIdToPriceMap.get(item.getSkuId()));
            });
            return infoList ;
        }
        return new ArrayList<>();
        }*/




    /**
     * 删除购物车内容
     *
     * @return
     */
    @Override
    public void deleteCart(Long skuId) {
        //获取当前登录对象
        Long userId = SecurityContextHolder.getUserId();
        //构建当前对象的购物车key
        String cartKey  = "user:cart:"+userId;
        BoundHashOperations<String,String,CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        ops.delete(skuId.toString());
    }

    /**
     * 更改购物车商品的勾选状态
     * @param skuId
     * @param isChecked
     */
    @Override
    public void updateCart(Long skuId, Integer isChecked) {
        //获取当前线程中的对象
        Long userId = SecurityContextHolder.getUserId();
        //为这个对象构建在redis中的key
        //这是dakey
        String cartKey = "user:cart:"+userId;
        //从缓存中拿到绑定关系
        BoundHashOperations<String,String,CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        //判断购物车中是否有sku商品
        if(ops.hasKey(skuId.toString())){
            CartInfo cartInfo = ops.get(skuId.toString());
            cartInfo.setIsChecked(isChecked);
            //将新的数据更新到缓存中
            ops.put(skuId.toString(),cartInfo);
        }
    }

    /**
     * 更新购物车商品全部的选中状态
     * @param isChecked
     */
    @Override
    public void allCheckCart(Integer isChecked) {
        //获取当前线程的userId
        Long userId = SecurityContextHolder.getUserId();
        //构建购物车的大key
        String cartKey="user:cart:"+userId;
        //从缓存中获取到大key的内容
        BoundHashOperations<String,String,CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        //取到cart大key对应的商品的信息map(类似)
        List<CartInfo> cartInfoList = ops.values();

        //遍历修改
        for (CartInfo cartInfo : cartInfoList) {
            cartInfo.setIsChecked(isChecked);
            //将每个商品的是否勾选状态放到缓存中
            ops.put(cartInfo.getSkuId().toString(),cartInfo);
        }

    }

    /**
     * 查询购物车中被勾选的商品
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        String cartKey="user:cart:"+userId;
        BoundHashOperations<String,String,CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = ops.values();
        if(!CollectionUtils.isEmpty(cartInfoList)){
            List<CartInfo> cartInfoListIsChecked = cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1).toList();
            return cartInfoListIsChecked;
        }
        return new ArrayList<>();
    }

    /**
     * 订单模块调用购物车，进行购物车商品的价格进行更新
     * @param userId
     * @return
     */
    @Override
    public Boolean updateCartPrice(Long userId) {
        //获取大key
        String cartKey="user:cart:"+userId;
        //获取到绑定关系
        BoundHashOperations<String,String,CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        //获取到购物车中的商品列表
        List<CartInfo> cartInfoList = ops.values();
        if(!CollectionUtils.isEmpty(cartInfoList)){//商品列表信息不为空
            //将列表转化为map集合，可通过kv形式进行取值
            List<CartInfo> cartInfoIsChecked = cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1).toList();
            //以上就是cartInfoList用流的形式转换成了map形式，以此拿出cartInfoList中，isChecked为1 的商品。并进行收集
            if(!CollectionUtils.isEmpty(cartInfoIsChecked)){
                //isChecked=1的列表不为空的话,将所有的skuId进行收集
                List<Long> skuIdList = cartInfoIsChecked.stream().map(cartInfo -> cartInfo.getSkuId()).toList();
                //远程调用product服务，根据skuId列表进行查询对应的所有的这些skuId的价格列表
                R<List<SkuPrice>> skuPriceListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
                if(skuPriceListResult.getCode()==R.FAIL){//远程调用报错就进行降级处理
                    throw new ServiceException(skuPriceListResult.getMsg());
                }
                //正常向下执行
                //拿出skuPriceListResult的数据，skuPriceListResult里面都是skuPrice列表
                List<SkuPrice> skuPriceList = skuPriceListResult.getData();
                //将skuPriceList数据转换成map形式
                Map<Long, BigDecimal> skuPriceToMap = skuPriceList.stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));
                for (CartInfo cartInfo : cartInfoIsChecked) {
                    cartInfo.setSkuPrice(skuPriceToMap.get(cartInfo.getSkuId()));
                    cartInfo.setCartPrice(skuPriceToMap.get(cartInfo.getSkuId()));
                    ops.put(cartInfo.getSkuId().toString(),cartInfo);
                }
                /*
                参考老师的价格更新
                for (CartInfo checkedCartInfo : cartInfoIsChecked) {
                    BigDecimal newPrice = skuPriceToMap.get(checkedCartInfo.getSkuId());
                    checkedCartInfo.setSkuPrice(newPrice);
                    checkedCartInfo.setCartPrice(newPrice);
                    ops.put(checkedCartInfo.getSkuId().toString(),checkedCartInfo);
                }*/
                return true;
            }
        }
        return false;
    }

    /**
     *
     * 删除购物车已经勾选的商品(对应的就是订单中的商品)
     * @param userId
     * @return
     */
    @Override
    public Boolean deleteCartCheckedList(Long userId) {
        //获取大key
        String cartKey="user:cart:"+userId;
        BoundHashOperations<String, String,CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = ops.values();
        if(!CollectionUtils.isEmpty(cartInfoList)){
            for (CartInfo cartInfo : cartInfoList) {
                if(cartInfo.getIsChecked().intValue()==1){
                    ops.delete(cartInfo.getSkuId().toString());
                }
            }
            //不为空，进行删除后，返回删除成功
            return true;
        }
        return false;
    }
}
